from functools import partial
import time

from osm_utils import *
from problem_generator import *
from map_problem import *


def RunAstar(road_map, initial, goal, c, h):
    #print 'RunAstar {} -> {}, c = {}, h = {}, result: '.format(initial, goal, c.__name__, h.__name__)
    print 'RunAstar {} -> {}, result: '.format(initial, goal)
    problem = MapProblem(initial, goal, road_map, c)
    #problem = search.InstrumentedProblem(problem)
    problem_h = partial(h, problem)
    start_time = time.clock()
    node, developed_nodes_count = search.astar_search(problem, problem_h)
    run_time = time.clock() - start_time
    # TRM debug?
    if node:
        path = node.path()
        print "\tdistance = {}, time = {}, stats = {}".format(
                                                sum(node.action.distance for node in path if node.action),
                                                sum(node.action.CalcTime() for node in path if node.action),
                                                problem)
    else:
        print "Astar failed :(... (are they reachable??)"
    return node, developed_nodes_count, run_time, node.path_cost


def RunWeightedAstar(road_map, initial, goal, c, h, weight):
    assert weight >= 0 and weight <= 1

    def weight_decorator(func, w):
        def w_func(*args, **kw):
            return w * func(*args, **kw)
        return w_func

    w_c = weight_decorator(c, 1 - weight)
    w_h = weight_decorator(h, weight)
    return RunAstar(road_map, initial, goal, w_c, w_h)


def RunSigmaAstar(road_map, initial, goal, weights):
    print 'Weights = ', weights, 
    C_sigma_p = partial(C_sigma, *weights)
    H_sigma_p = partial(H_sigma, *weights)
    return RunAstar(road_map, initial, goal, C_sigma_p, H_sigma_p)